package minio

import (
	"context"
	"github.com/minio/minio-go/v7"
	"github.com/minio/minio-go/v7/pkg/credentials"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"golang-sgg-daijia/pkg/log"
	"io"
)

type MinioClient interface {
	PutObject(
		ctx context.Context, objectName string, r io.Reader, size int64) (string ,error)
}

type minioClient struct {
	minioCli *minio.Client
	logger *log.Logger
	conf   *viper.Viper
}

func NewMinioClient(
	minioCli *minio.Client,
	logger *log.Logger,
	conf *viper.Viper,
) MinioClient {
	return &minioClient{
		minioCli: minioCli,
		logger: logger,
		conf:   conf,
	}
}

func NewMinioCli(conf *viper.Viper) *minio.Client {
	endpoint := conf.GetString("data.minio.endpoint_url")
	accessKeyID := conf.GetString("data.minio.access_key")
	secretAccessKey := conf.GetString("data.minio.secret_key")

	// Initialize minio client object.
	minioCli, err := minio.New(endpoint, &minio.Options{
		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
		Secure: false,
	})
	if err != nil {
		panic(err)
	}
	return minioCli
}

func (cli *minioClient) PutObject(
	ctx context.Context, objectName string, r io.Reader, size int64) (string ,error) {

	bucketName := cli.conf.GetString("data.minio.bucket_name")

	// 判断桶是否存在
	found, err := cli.minioCli.BucketExists(ctx, bucketName)
	if err != nil {
		cli.logger.WithContext(ctx).Error("minioClient|PutObject|BucketExists", zap.Any("data", map[string]interface{}{
			"bucketName": bucketName,
		}), zap.Error(err))
	}
	if !found {
		// 创建桶
		if err != nil {
			cli.logger.WithContext(ctx).Error("minioClient|PutObject|MakeBucket", zap.Any("data", map[string]interface{}{
				"bucketName": bucketName,
			}), zap.Error(err))
			return "", err
		}
	}
	err = cli.minioCli.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{})
	if err != nil {
		// Check to see if we already own this bucket (which happens if you run this twice)
		exists, errBucketExists := cli.minioCli.BucketExists(ctx, bucketName)
		if !(errBucketExists == nil && exists) {
			// 创建桶失败
			cli.logger.WithContext(ctx).Error("minioClient|PutObject|MakeBucket", zap.Any("data", map[string]interface{}{
				"bucketName": bucketName,
			}), zap.Error(err))
			return "", err
		}
	}

	_, err = cli.minioCli.PutObject(ctx, bucketName, objectName, r, size, minio.PutObjectOptions{})
	if err != nil {
		cli.logger.WithContext(ctx).Error("minioClient|PutObject|PutObject", zap.Any("data", map[string]interface{}{
			"objectName": objectName,
			"size":       size,
		}), zap.Error(err))
		return "", err
	}
	endpoint := cli.conf.GetString("data.minio.endpoint_url")

	return endpoint + "/" + bucketName + "/" + objectName, nil
}
